local AddOnName, Env = ...; local ADDON, DT = Env[1], Env[1].development
-- ~~| Libraries |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local AceConfigRegistry	= LibStub("AceConfigRegistry-3.0")
local DiesalStyle 		= LibStub("DiesalStyle-1.0")
local DiesalGUI 			= LibStub("DiesalGUI-1.0")
local DiesalMenu 			= LibStub('DiesalMenu-1.0')
-- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local pairs, ipairs							= pairs,ipairs
local type	 									= type
local gsub, sub, find, format 			= string.gsub, string.sub, string.find, string.format
local concat									= table.concat
-- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~| RotationConfig |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- ~~| RotationConfig StyleSheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local windowStyleSheet = {		
	
}
local dropdownStyleSheet = {
	['frame-arrow'] = {
		type			= 'texture',
		layer			= 'BORDER',
		alpha 		= 0,
	},
}
local ConSelectStyleSheet = {		
	['frame-highlight'] = {			
		type			= 'texture',
		layer			= 'BORDER',
		color			= 'ffffff',
		gradient		= 'VERTICAL',
		alpha 		= .07,
		alphaEnd		= .12,
		offset		= {0,0,0,nil},
		height		= 11,
	},
	['frame-inline'] = {		
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,
		offset		= 0,	
	},		
	['frame-arrow'] = {
		type			= 'texture',
		layer			= 'BORDER',
		alpha 		= 0,
	},
}	
local lockButtonNormal = {
	type			= 'texture',
	alpha 		= .7,
}
local lockButtonOver = {
	type			= 'texture',
	alpha 		= 1,
}
local lockButtonDisabled = {
	type			= 'texture',
	alpha 		= .3,
}
-- ~~| RotationConfig Locals |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local GREY75		= ADDON:GetTxtColor('c0c0c0')
local GREY50		= ADDON:GetTxtColor('808080')
local BLUE			= ADDON:GetTxtColor('00aaff')	
local ORANGE		= ADDON:GetTxtColor('e6c000') 
local PURPLE		= ADDON:GetTxtColor('9900e5') 
local RED			= ADDON:GetTxtColor('ff0000') 
local YELLOW		= ADDON:GetTxtColor('ffff00')

-- ~~| RotationConfig Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local methods = {
	['ProfileUpdate'] = function(self)
		local db			= self.db
		local frame		= self.frame
		-- ~~ Update Rows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if next(self.settings.configs) then
			for key,config in pairs(self.settings.configs) do
				self:SetupConfigDB(config)
			end
			self:UpdateOptions()
		end
		-- ~~ Update Position ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		frame:ClearAllPoints()
		if db.top and db.left then
			frame:SetPoint("TOP",UIParent,"BOTTOM",0,db.top)
			frame:SetPoint("LEFT",UIParent,"LEFT",db.left,0)
		else
			frame:SetPoint("CENTER",UIParent,"CENTER")
		end
		frame:SetWidth(db.width)
	end,
	['Update'] = function(self)
		-- Only called from core
		local db			= self.db
		local frame		= self.frame

		frame[db.show and "Show" or "Hide"](frame)		
	end,
	['UpdateConfigs'] = function(self)
		wipe(self.settings.configs)
		wipe(self.settings.configList)
		
		for r = 1, 6 do 
			if ADDON.Rotations[r].data and ADDON.Rotations[r].data.configs and ADDON.Rotations[r].data.configs[1] then 
				for c = 1, #ADDON.Rotations[r].data.configs do
					local config = ADDON.Rotations[r].data.configs[c]
					-- ~~ set option IDs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					for s = 1, #config do
						for o = 1, #config[s] do
							local option = config[s][o]
							if option.name then option.id = format( '%s_%s_%s_%s',config.id,ADDON:CreateID(config[s].section),option.type,ADDON:CreateID(option.name) )	end
						end					
					end					
					-- ~~ Add config ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					self.settings.configs[config.id] = config
					-- ~~ Update config Select List ~~~~~~~~~~~~~~~~~~~~
					self.settings.configList[config.id] = format('%s%s %s%s',GREY75,config.name,BLUE,ADDON.Rotations[r].data.author or '')
					-- ~~ Setup config Database ~~~~~~~~~~~~~~~~~~~~~~~~
					self:SetupConfigDB(config)					
				end
			end			
		end		
		
		self.configSelect:SetList(self.settings.configList)
		
		if self.settings.activeConfigID and self.settings.configs[self.settings.activeConfigID] then -- previously active config still avaiable 
			self:SetActiveConfig(self.settings.activeConfigID)	
		else -- check for a config to set as active
			if next(self.settings.configs) then -- set next rotation found as active
				self.window:SetSettings({footer = true},true)
				self:SetActiveConfig(next(self.settings.configs))					
			else -- TBD no configs, leaves exisitng loading config active if any
				self.settings.activeConfig 	= nil
				self.settings.activeConfigID	= nil 				
				self.accordian:ReleaseChildren()
				self.configSelect:EnableMouse(false)
				self.configSelect:SetText('No Configurations Loaded')
				self.window:SetSettings({
					footer 	= false,
					height	= 35,
				},true)
			end
		end	
		
	end,	
	['SetupConfigDB'] = function(self,config)
		-- setup new Database entry
		if not self.db.configs[config.id] then
			self.db.configs[config.id] = {
				currentSet 		= 1,
				id 				= config.id,
				sets 				= {},
				sections			= {},
			}			
		end
		-- update database entry
		local configDB = self.db.configs[config.id]
		for setnum = 1, 9 do	-- NUMBER OF SETS
			-- setup new set entry
			if not configDB.sets[setnum] then
				configDB.sets[setnum] = {
					name	= "set"..setnum,
					id 	= configDB.id,
				}
			end
			-- update options
			for s = 1, #config do
				-- setup section states				
				for o = 1, #config[s] do				
					if config[s][o].name then
						local option = config[s][o]
						if not configDB.sets[setnum][option.id] then
							-- setup new option entry
							configDB.sets[setnum][option.id] = {
								id			= option.id,
								enable	= option.enable,
								value		= option.value,
								type		= option.type,
							}
						else
							-- update option entry
							local optionDB = configDB.sets[setnum][option.id]
							if optionDB.type ~= option.type then
								optionDB.type	= option.type
								optionDB.value	= option.value
							end
						end
					end
				end
			end
		end
	end,
	['SetActiveConfig'] = function(self, configID)
		if not self.settings.configs[configID] then return end
		
		-- ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~		
		local sections	= self.settings.sections
		local config 	= self.settings.configs[configID]
		
		self.settings.activeConfig 	= config
		self.settings.activeConfigID 	= configID
		-- ~~ Clear Rows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.accordian:ReleaseChildren()
		-- ~~ Build Config ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.accordian:Build(config)		
		-- ~~ Update ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.configSelect:EnableMouse(true)
		self.configSelect:SetValue(configID)
		self:UpdateVars()
		self:UpdateOptions()
	end,
	['UpdateOptions'] = function(self)
		local activeDB = self.db.configs[self.settings.activeConfigID]
		local option
		for s = 1, #self.accordian.children do			
			for o = 1 , #self.accordian.children[s].children do				
				option = self.accordian.children[s].children[o]
				option[self.db.lock and "Lock" or "Unlock"](option)
				option:Update(activeDB.sets[activeDB.currentSet][option.settings.data.id])
			end
			self.accordian.children[s]:Update(activeDB.sections)
		end
		self:UpdateSetList()
	end,
	['UpdateVars'] = function(self)
		if not self.configVars:IsVisible() then return end		
		local option
		
		local vars = {format('%sConfigID: %s%s%s\n\nVariables for rotation developers\n',BLUE,GREY75,self.settings.activeConfig.id,GREY50,varUse)}
		for s = 1, #self.settings.activeConfig do
			for o = 1, #self.settings.activeConfig[s] do
				option = self.settings.activeConfig[s][o]
				if option.type:lower() ~= 'divider' then
					if option.toggle ~= false then
						vars[#vars+1] = GREY75..option.id..'_Enable'
					end
					
					if option.type:lower() == 'hotkey' then
						vars[#vars+1] = format('%sIsHotkeys%s( %s%s_Value %s)',PURPLE,ORANGE,GREY75,option.id,ORANGE)
					elseif option.type:lower() ~= 'toggle' then
						vars[#vars+1] = GREY75..option.id..'_Value'
					end					
				end				
			end
		end
			
		self.scrollingEditBox:SetText(concat(vars,'\n'))
	end,
	['UpdateSetList'] = function(self)
		local activeDB = self.db.configs[self.settings.activeConfigID]
		for i = 1, #activeDB.sets do
			self.settings.orderedSetList[i] = i
			self.settings.setList[i] = activeDB.sets[i].name
		end
		self.setSelect:SetList(self.settings.setList,self.settings.orderedSetList)
		self.setSelect:SetValue(activeDB.currentSet)
	end,
	['RenameSet'] = function(self,key,value)
		self.db.configs[self.settings.activeConfigID].sets[key].name = value
		self:UpdateSetList()
	end,
	['Show'] = function(self)
		self.frame:Show()
	end,
	['Hide'] = function(self)
		self.frame:Hide()
	end,
}
-- ~~| RotationConfig Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function ADDON:constructRotationConfig()
	local self = {}
	self.db = ADDON.db.profile.rotationConfig
	-- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	local settings = {
		configs 			= {},
		rows 				= {},
		configList 		= {},
		setList			= {},
		orderedSetList	= {},
	}
	self.settings = settings
	-- ~~ Construct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	local window = DiesalGUI:Create('Window')	
	window:AddStyleSheet(windowStyleSheet)
	window:SetSettings({
		top				= self.db.top,
		left				= self.db.left,
		header			= true,
		headerHeight	= 17,
		footerHeight	= 24,
		height	 		= 35,
		width				= self.db.width,
		minWidth 		= 190,
		minHeight 		= 10,
		sizerWidth		= 10,
		sizerB			= false,
		sizerBR			= false,
	},true)
	window:SetTitle(RED..AddOnName,GREY75..'Rotation Config')	
	window:SetEventListener('OnSizeChanged', function(this,event,width,height)
		self.db.width 	= width		
	end)
	window:SetEventListener('OnDragStop', function(this,event,left,top)
		self.db.left 	= left
		self.db.top 	= top
	end)
	window:SetEventListener('OnClose', function(this,event)
		self.db.show = false
		AceConfigRegistry:NotifyChange(AddOnName)
	end)	
	window.frame:SetClampRectInsets(1000,-1000,-1000,1000)

	local configSelect = DiesalGUI:Create('Dropdown')
	configSelect:AddStyleSheet(ConSelectStyleSheet)
	configSelect:SetParent(window.header)
	configSelect:SetAllPoints()	
	configSelect.text:SetJustifyH("CENTER")
	configSelect.text:SetPoint("BOTTOMRIGHT", -4, -1)
	configSelect:SetText('No Configurations Loaded')
	configSelect:EnableMouse(false)
	configSelect:SetEventListener('OnEnter', function(this)
		if not ADDON.RotationConfig.db.tooltips then return end
		GameTooltip:SetOwner(configSelect.frame, "ANCHOR_TOPRIGHT",0,2)
		GameTooltip:AddLine(format('%sConfig Selector',BLUE))
		GameTooltip:AddLine(' ')
		GameTooltip:AddDoubleLine(format('%sRight Click:',BLUE),format('%sSelect Config',YELLOW))
		GameTooltip:AddDoubleLine(format('%sLeft  Click:',BLUE),format('%sConfig Variables',YELLOW))
		GameTooltip:Show()
	end)
	configSelect:SetEventListener('OnLeave', function(this)
		GameTooltip:Hide()
	end)
	configSelect:SetEventListener('OnValueSelected', function(this,event,key)
		self:SetActiveConfig(key)
	end)
	configSelect:SetEventListener('OnMouseUp', function(this,event,button)
		if button =='RightButton' then
			local configVars = self.configVars
			configVars[configVars:IsVisible() and 'Hide' or 'Show'](configVars)
			self:UpdateVars()
		end
	end)
	
	local accordian = DiesalGUI:Create('ConAccordian')
	accordian:SetParentObject(window)	
	accordian:SetEventListener('OnHeightChange', function(this,event,height)
	window.frame:EnableMouse(false) 
	window.frame:SetMovable(false)
	window.frame:SetResizable(false)	
		self.frame:SetHeight( (window.settings.height - window.content:GetHeight()) + height )
	window.frame:EnableMouse(true) 
	window.frame:SetMovable(true)
	window.frame:SetResizable(true)				
	end)
	accordian:SetAllPoints()	

	local setSelect = DiesalGUI:Create('ComboBox')
	setSelect:SetParent(window.footer)
	setSelect:SetPoint('TOPLEFT',18,-5)
	setSelect:SetPoint('TOPRIGHT',-3,-5)
	setSelect:SetHeight(16)
	setSelect:SetEventListener('OnValueSelected', function(this,event,key)
		self.db.configs[self.settings.activeConfigID].currentSet = key
		self:UpdateOptions()
	end)
	setSelect:SetEventListener('OnRenameValue', function(this,event,key,value)
		local PQI_RENAMESET 	= StaticPopup_Show("PQI_RENAMESET")
		PQI_RENAMESET.key  	= key
		PQI_RENAMESET.value 	= value
	end)	
	setSelect.button:SetScript("OnEnter", function(this) 
		if not ADDON.RotationConfig.db.tooltips then return end
		GameTooltip:SetOwner(setSelect.button, "ANCHOR_TOPRIGHT",0,2)
		GameTooltip:AddLine('Select Set')		
		GameTooltip:Show()
	end)
	setSelect.button:SetScript("OnLeave", function(this) GameTooltip:Hide() end)
	setSelect.editBox:SetScript("OnEnter", function(this)
		if not ADDON.RotationConfig.db.tooltips then return end
		GameTooltip:SetOwner(setSelect.editBox, "ANCHOR_TOPRIGHT",0,2)
		GameTooltip:AddLine('Rename Set')		
		GameTooltip:Show()
	end)
	setSelect.editBox:SetScript("OnLeave", function(this) GameTooltip:Hide() end)

	local lockButton = DiesalGUI:Create('Button')
	lockButton:SetParent(window.footer)
	lockButton:SetPoint('TOPLEFT',0,-3)
	lockButton:SetSettings({
		width			= 20,
		height		= 20,
	},true)
	lockButton:SetStyle('frame',{
		type			= 'texture',
		texFile		='DiesalGUIcons',
		texCoord		= {self.db.lock and 11 or 12,5,16,256,128},
		alpha 		= .7,
		offset		= {-2,nil,-2,nil},
		width			= 16,
		height		= 16,
	})
	lockButton:SetEventListener('OnEnter', 	function()
		lockButton:SetStyle('frame',lockButtonOver)
		if not ADDON.RotationConfig.db.tooltips then return end
		GameTooltip:SetOwner(lockButton.frame, "ANCHOR_TOPRIGHT",0,2)
		GameTooltip:AddLine('Lock Config')		
		GameTooltip:Show()
	end)
	lockButton:SetEventListener('OnLeave', 	function()
		lockButton:SetStyle('frame',lockButtonNormal)
		GameTooltip:Hide()
	end)
	lockButton:SetEventListener('OnDisable', 	function() lockButton:SetStyle('frame',lockButtonDisabled)	end)
	lockButton:SetEventListener('OnEnable', 	function() lockButton:SetStyle('frame',lockButtonNormal)		end)
	lockButton:SetEventListener('OnClick', 	function()
		self.db.lock = not self.db.lock	
		local option
		for s = 1, #self.accordian.children do			
			for o = 1 , #self.accordian.children[s].children do				
				option = self.accordian.children[s].children[o]
				option[self.db.lock and "Lock" or "Unlock"](option)				
			end
		end		
		lockButton:SetStyle('frame',{ type = 'texture', texCoord = {self.db.lock and 11 or 12,5,16,256,128} })
	end)

	local configVars = DiesalGUI:Create('Window')
	configVars:SetSettings({
		height	 		= 300,
		width				= 500,
		minWidth 		= 500,
		minHeight 		= 200,
		sizerR			= false,
		sizerB			= false,
		sizerBRHeight	= 32,
		sizerBRWidth	= 32,
	},true)
	configVars:SetTitle(RED..AddOnName,GREY75..'Config Variables')	
	configVars:SetStyle('content-background',{
		type			= 'texture',
		layer			= 'BACKGROUND',
		color			= '171717',
		offset		= 0,
	})
	configVars.sizerBR:SetPoint("BOTTOMRIGHT",configVars.frame,"BOTTOMRIGHT",-8,0)
	configVars.sizerBR:SetFrameLevel(100)
	configVars:Hide()
	local scrollingEditBox = DiesalGUI:Create('ScrollingEditBox')
	scrollingEditBox:SetParentObject(configVars)
	scrollingEditBox:SetSettings({
		contentPadTop		= 4,
		contentPadBottom	= 3,
		contentPadLeft		= 3,
		contentPadRight	= 3,
	},true)
	scrollingEditBox:SetPoint('TOPLEFT',1,-1)
	scrollingEditBox:SetPoint('BOTTOMRIGHT',-2,1)
	-- ~~ Frames ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	self.window 				= window
	self.frame 					= window.frame
	
	self.accordian 			= accordian

	self.configSelect 		= configSelect
	self.setSelect 			= setSelect
	self.lockButton 			= lockButton

	self.configVars 			= configVars
	self.scrollingEditBox 	= scrollingEditBox
	-- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	for method, func in pairs(methods) do
		self[method] = func
	end
	-- ~~ Style ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	-- self.textures = {}
	-- DiesalStyle:AddObjectStyleSheet(self,styleSheet)
	-- ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	self:Hide()
	return self
end